<?php
// +----------------------------------------------------------------------
// | zhanshop-admin / IndexService.php    [ 2023/8/11 11:42 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2011~2023 zhangqiquan All rights reserved.
// +----------------------------------------------------------------------
// | Author: zhangqiquan <768617998@qq.com>
// +----------------------------------------------------------------------
declare (strict_types=1);

namespace app\api\admin\v1\service;

use app\helper\Password;
use zhanshop\App;
use zhanshop\console\command\Server;
use zhanshop\client\Httpclient;

class IndexService extends BaseService
{
    /**
     * 获取后台菜单
     * @param int $userId
     * @param int $roleId
     * @return array
     * @throws \Exception
     */
    public function getIndex(int $userId, int $roleId){
        $data = App::database()->model('system_menu')->get($roleId);
        // 每次刷新首页都会刷新权限菜单的缓存
        if($data){
            $menuIds = array_column($data, 'id');
            $this->setRoleMenu($roleId, $menuIds);
        }
        $user = App::database()->model("system_user")->where(['user_id' => $userId, 'enabled' => '1'])->field('user_id,user_name,avatar')->find();
        if($user == false) App::error()->setError('用户不存在或被禁用', 10001);
        return ['menu' => $data, 'user' => $user];
    }

    /**
     * 后台首页统计假数据
     * @param int $userId
     * @param int $roleId
     * @return array
     */
    public function getMain(){
        $outData = (new Httpclient())->request("http://zhanshop-nginx/zhanshop-status")['body'];
        $connections = 0;
        $accept = 0;
        $requests = 0;
        if($outData){
            $connectionsLine = explode("\n", $outData);
            $arr = explode("Active connections: ", $connectionsLine[0]);
            $connections = 0;
            $accept = 0;
            $requests = 0;
            if(isset($arr[1])){
                $connections = intval($arr[1]);
            }
            if(isset($connectionsLine[2])){
                $arr = explode(" ", $connectionsLine[2]);
                $accept = intval($arr[2] ?? 0);
                $requests = intval($arr[3] ?? 0);
            }
        }
        $nginxRequestCountList = $this->nginxRequestCountList();
        return [
            'nginx' => [
                'connections' => $connections,
                'accept' => $accept,
                'requests' => $requests,
                'top_connections' => 0,
                'count_connections_list' => $this->nginxConnectionsCountList(),
                'count_request_list' => $nginxRequestCountList['request'],
                'count_visitor_list' => $nginxRequestCountList['visitor'],
            ],
            'space' => [
                'disk' => $this->spaceStats('disk'),
                'mysql' => $this->spaceStats('mysql'),
                'redis' => $this->spaceStats('redis'),
            ],
            'stats' => $this->stats(),
        ];
    }

    public function getEcharts(string $type, string $date)
    {
        $data = [
            'dates' => [date('Ymd', strtotime('-1 day')),date('Ymd', strtotime('-2 day')),date('Ymd', strtotime('-3 day')),date('Ymd', strtotime('-4 day')),date('Ymd', strtotime('-5 day')),date('Ymd', strtotime('-6 day')),date('Ymd', strtotime('-7 day')),date('Ymd', strtotime('-8 day')),date('Ymd', strtotime('-9 day')),date('Ymd', strtotime('-10 day')),date('Ymd', strtotime('-11 day')),date('Ymd', strtotime('-12 day')),date('Ymd', strtotime('-13 day')),date('Ymd', strtotime('-14 day'))],
            'connections' => [
                'time' => [],
                'value' => [],
                'realtime' => [],
                'realval' => [],
            ],
            'requestip100' => []
        ];

        $statsLog = App::rootPath().'/docker/nginx/stats/connections-'.date('Ymd').'.log';
        if(file_exists($statsLog)){
            $arr = explode("\n", file_get_contents($statsLog));
            foreach ($arr as $k => $v){
                if($v){
                    $rows = explode(',', $v);
                    $data['connections']['realtime'][] = $rows[0];
                    $data['connections']['realval'][] = $rows[1];
                }
            }
        }

        $statsLog = App::rootPath().'/docker/nginx/stats/connections-'.$date.'.log';
        if(file_exists($statsLog)){
            $arr = explode("\n", file_get_contents($statsLog));
            foreach ($arr as $k => $v){
                if($v){
                    $rows = explode(',', $v);
                    $data['connections']['time'][] = $rows[0];
                    $data['connections']['value'][] = $rows[1];
                }
            }
        }

        $statJsonFile = App::rootPath().'/docker/nginx/stats/stats-'.$date.'.log';
        if(file_exists($statJsonFile)){
            $statArr = json_decode(file_get_contents($statJsonFile), true);
            $topNumber = 0;
            foreach ($statArr['requestip100'] ?? [] as $ip => $val){
                $data['requestip100'][$ip] = $val;
                $topNumber++;
                if($topNumber >= 100) break;
            }
        }

        return $data;
    }

    /**
     * @param int $limit
     * @return array
     */
    protected function nginxRequestCountList(int $limit = 30)
    {
        $data = [
            'request' => [
                'time' => [],
                'value' => [],
                'upday_request' => 0
            ],
            'visitor' => [
                'time' => [],
                'value' => [],
            ],
        ];

        for($i = $limit; $i > 0; $i--){
            $date = date('Ymd', strtotime('-'.$i.' day'));
            $statJsonFile = App::rootPath().'/docker/nginx/stats/stats-'.$date.'.log';
            if(file_exists($statJsonFile)){
                $statArr = json_decode(file_get_contents($statJsonFile), true);
                if($statArr){
                    $requestSum = $statArr['area_stats']['total_pv'] ?? 0;
                    $data['request']['time'][] = $date;
                    $data['request']['value'][] = $requestSum;

                    $requestSum = $statArr['area_stats']['total_uv'] ?? 0;
                    $data['visitor']['time'][] = $date;
                    $data['visitor']['value'][] = $requestSum;
                }
            }
        }
        $data['request']['upday_request'] = $statArr['area_stats']['total_pv'] ?? 0;
        return $data;
    }


    /**
     * @param int $limit
     * @return array
     */
    protected function nginxConnectionsCountList(int $limit = 60)
    {
        $data = [
            'time' => [],
            'value' => []
        ];
        $statsLog = App::rootPath().'/docker/nginx/stats/connections-'.date('Ymd').'.log';
        if(file_exists($statsLog)){
            $arr = explode("\n", file_get_contents($statsLog));
            krsort($arr);
            $arr = array_values($arr);
            unset($arr[0]);

            for($i = 1; $i <= $limit; $i++){
                if(isset($arr[$i])){
                    $rows = explode(',', $arr[$i]);
                    $data['time'][] = $rows[0];
                    $data['value'][] = $rows[1];
                }
            }
        }
        krsort($data['time']);
        $data['time'] = array_values($data['time']);

        krsort($data['value']);
        $data['value'] = array_values($data['value']);
        return $data;
    }

    protected function stats()
    {
        $stats = Server::$server->stats();
        $stats['start_time'] = date('Y-m-d H:i:s', $stats['start_time']);
        $stats['total_recv_bytes'] = round($stats['total_recv_bytes'] / 1024 / 1024, 2).' MB';
        $stats['total_send_bytes'] = round($stats['total_send_bytes'] / 1024 / 1024, 2).' MB';
        $list = [];
        $field = [
            'start_time' => '启动时间',
            'connection_num' => '当前连接数',
            //'abort_count' => '拒绝连接数',
            //'accept_count' => '接受连接数',
            //'close_count' => '关闭连接数',
            'worker_num' => '工作进程数',
            'task_worker_num' => '任务进程数',
            'idle_worker_num' => '空闲工作进程数',
            'request_count' => '收到请求数',
            'response_count' => '响应请求数',
            'total_recv_bytes' => '接收数据总数',
            'total_send_bytes' => '发送数据总数',
//            'min_fd' => '最小通信符ID',
//            'max_fd' => '最大通信符ID',
            'task_idle_worker_num' => '空闲任务进程数',
            'tasking_num' => '正在工作任务进程数',
//            'coroutine_num' => '当前协程数',
//            'coroutine_peek_num' => '全部协程数',
        ];
        foreach($stats as $k => $v){
            if(isset($field[$k])){
                $list[$field[$k]] = $v;
            }
        }
        return $list;
    }

    private function spaceStats(string $type)
    {
        $data = [
            'time' => [],
            'value' => []
        ];
        $statsLog = App::rootPath().'/runtime/devops/'.$type.'/'.date('Ymd').'.log';
        if(file_exists($statsLog)){
            $arr = explode("\n", file_get_contents($statsLog));
            foreach ($arr as $k => $v){
                $arr = explode("###", $v);
                if(count($arr) == 2){
                  $json = json_decode($arr[1] ?? '', true);
                  $data['time'][] = $arr[0];
                  $data['value'][] = $json['used_rate'];
                }
            }
        }
        return $data;
    }


    /**
     * 获取当前用户信息
     * @return array
     */
    public function getUser(int $userId){
        return App::database()->model("system_user")->where(['user_id' => $userId])->find();
    }

    /**
     * 更新当前用户信息
     * @param int $userId
     * @param array $data
     * @return array
     * @throws \Exception
     */
    public function postUser(int $userId, array $data){
        $userName = App::database()->model("system_user")->where(['user_id' => $userId])->value("user_name");
        if($userName == false) App::error()->setError('没有相关用户信息', 404);
        App::database()->model("system_user")->where(['user_id' => $userId])->update(
            [
                'avatar' => $data['avatar'],
                'password' => Password::hashEncode($data['password'], $userName),
            ]
        );
        return [];
    }

    public function postTable(int $roleId, string $menuId, string $action){
        $this->permission($roleId, $menuId); // 菜单权限验证
        $this->getFinder($menuId)->$action();
    }
}